#!/usr/bin/python3

import sys
import librungame.util
import librungame.game.windows
import librungame.runner


def die(msg):
    print(msg, file=sys.stderr)
    sys.exit(1)


def run():
    sysInfo = librungame.util.SysInfo()
    game = librungame.game.windows.PlantsVsZombies("/opt/plants-vs-zombies")
    runner = librungame.runner.Wine(verbose=2)
    with librungame.RunGame(sysInfo, "plants-vs-zombies", game, runner).context(edit_or_run=False) as rg:
        game.apply_fullscreen_or_windowed(True)
        rg.run("main")


def edit(op, args):
    sysInfo = librungame.util.SysInfo()
    game = librungame.game.windows.PlantsVsZombies("/opt/plants-vs-zombies")
    runner = librungame.runner.Wine(verbose=0)
    with librungame.RunGame(sysInfo, "plants-vs-zombies", game, runner).context(edit_or_run=True):
        if op == "list":
            userList = game.list_users()
            if len(userList) > 0:
                print("Users:")
                for c in userList:
                    print("    %s" % (c))
            else:
                print("No user file found.")
        elif op == "inspect":
            with game.open_user_file(args.user_name) as cf:
                print("Money: %i" % (cf.get_money()))
        elif op == "modify":
            with game.open_user_file(args.user_name) as cf:
                if args.new_user_name is not None:
                    cf.set_name(args.new_user_name)
                if args.new_money is not None:
                    cf.set_money(args.new_money)
                cf.save()
        else:
            assert False


class ArgParser:

    progName = "plants-vs-zombies"

    class ParseError(Exception):
        pass

    @classmethod
    def print_help(cls):
        print('%s is the main entrance of game Neighbours from Hell.' % (cls.progName))
        print('   Run the game:')
        print('       %s' % (cls.progName))
        print('   Manage user files:')
        print('       %s -l                        # List users' % (cls.progName))
        print('       %s -i <user>                 # Inspect a user file' % (cls.progName))
        print("       %s -N <new-name> <user>      # Change user name" % (cls.progName))
        print('       %s -M <new-money> <user>     # Set money' % (cls.progName))
        print('')

    @staticmethod
    def parseHelp():
        if sys.argv[1] == "-h" or sys.argv[1] == "--help":
            return DynObject()
        else:
            return None

    @classmethod
    def parseList(cls):
        if sys.argv[1] != "-l":
            return None

        i = 1
        while i < len(sys.argv):
            if sys.argv[i] == "-l":
                i += 1
                continue
            break
        if i < len(sys.argv):
            raise cls.ParseError("Error: Redundant argument(s) found.")
        return DynObject()

    @classmethod
    def parseInspect(cls):
        if sys.argv[1] != "-i":
            return None

        ret = DynObject()
        ret.user_name = None

        i = 1
        while i < len(sys.argv):
            if sys.argv[i] == "-i":
                i += 1
                continue
            if ret.user_name is None:
                ret.user_name = sys.argv[i]
                i += 1
                continue
            break
        if i < len(sys.argv):
            raise cls.ParseError("Error: Redundant argument(s) found.")
        if ret.user_name is None:
            raise cls.ParseError("Error: No user specified.")
        return ret

    @classmethod
    def parseModify(cls):
        if sys.argv[1] not in ["-N", "-M"]:
            return None

        ret = DynObject()
        ret.new_user_name = None
        ret.new_money = None
        ret.user_name = None

        i = 1
        bFound = False
        while i < len(sys.argv):
            if sys.argv[i] == "-N":
                if ret.new_city_name is not None:
                    raise cls.ParseError('Error: Multiple "-N" arguments found.')
                if i + 1 >= len(sys.argv):
                    raise cls.ParseError('Error: New user name must be specified after "-N" argument.')
                ret.new_profile_name = sys.argv[i + 1]
                i += 2
                bFound = True
                continue
            if sys.argv[i] == "-M":
                if ret.new_money is not None:
                    raise cls.ParseError('Error: Multiple "-M" arguments found.')
                if i + 1 >= len(sys.argv):
                    raise cls.ParseError('Error: New money value must be specified after "-M" argument.')
                try:
                    ret.new_money = int(sys.argv[i + 1])
                except ValueError:
                    raise cls.ParseError('Error: New money value must be integer.')
                i += 2
                bFound = True
                continue
            if ret.user_name is None:
                ret.user_name = sys.argv[i]
                i += 1
                continue
            break
        if i < len(sys.argv):
            raise cls.ParseError("Error: Redundant argument(s) found.")
        if not bFound:
            raise cls.ParseError("Error: No modify operation specified.")
        if ret.user_name is None:
            raise cls.ParseError("Error: No user specified.")
        return ret


class DynObject:
    pass


if __name__ == "__main__":
    op = None
    try:
        if len(sys.argv) <= 1:
            run()
            sys.exit(0)

        args = ArgParser.parseHelp()
        if args is not None:
            ArgParser.print_help()
            sys.exit(0)

        if op is None:
            args = ArgParser.parseList()
            if args is not None:
                op = "list"
        if op is None:
            args = ArgParser.parseInspect()
            if args is not None:
                op = "inspect"
        if op is None:
            args = ArgParser.parseModify()
            if args is not None:
                op = "modify"
        if op is None:
            raise ArgParser.ParseError('Argument(s) invalid.')
        edit(op, args)
    except ArgParser.ParseError as e:
        print(str(e) + ' Use "%s -h" to see usage information.' % (ArgParser.progName), file=sys.stderr)
        sys.exit(1)
